home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: merge.c,v 0.91 1994/02/20 00:53:25 zhao Pre-Release $
- *
- *. This file is part of BIT shareware package. After the two weeks of
- * free evaluation period, you are encouraged (required) to register
- * your copy for a small registration fee, which is $35 for personal use
- * and $50 for commercial, government and institutional use.
- *
- * Copyright(c) 1993, 1994 by T.C. Zhao.
- * All rights reserved.
- *
- * Permission to use, copy, and distribute this software in its entirety
- * for non-commercial purposes is hereby granted, provided that the
- * above shareware and copyright notices and this permission notice
- * appear in all copies and their documentation.
- *
- * This software may be modified for your own use, but modified versions
- * may not be distributed without prior consent of the author.
- *
- * This software is provided "as is" without expressed or implied
- * warranty of any kind.
- *
- *.
- *
- * Purpose:
- * Merge/concatinate/overlay two or more images to form a
- * single image.
- *
- */
-
- #if !defined(lint) && defined(F_ID)
- char *id_mg = "$Id: merge.c,v 0.91 1994/02/20 00:53:25 zhao Pre-Release $";
- #endif
-
- #include "bit.h"
- #include "extern.h"
-
- /******************* Limits and defines **************************/
-
- #define MAXOFF 300.0 /* max overlapping */
- #define ImageOK (ir->w > 0) /* if new image load */
-
- /***************** Local variables ******************************/
-
- static Rect_t imrect, *imr; /* current image size (global) */
- static Rect_t iirect, *ir; /* loaded image size */
- static IPTR mi; /* the load image itself */
- static IPTR oim; /* input image */
- static int showmi = 0; /* if show image while moving */
- static int autosize; /* if update image size */
- static int alignreq = 4; /* requested allignment */
- static int sep; /* sepetation */
- static int mergebot; /* which on top if overlap */
- static int fillc[4]; /* fill color */
- static FL_FORM *imerge;
- static int offx, offy; /* where original image is */
-
- /******* Possible operations on the image ******************/
- typedef struct
- {
- const char *name; /* operation name */
- int matop; /* known by the matrix rouines */
- }
- Matop;
-
- static Matop matops[] =
- {
- {"Overwrite", O_NONE,},
- {" Add ", O_ADD},
- {" Sub ", O_SUB},
- {" Diff ", O_DIFF},
- {" XOR ", O_XOR},
- {" Mask ", O_MASK}
- };
-
- static Matop *mop = matops;
-
- /******* Local functions **************************************/
-
- static void create_form_imerge(void);
- static int merge_init(IPTR, int);
-
- static void
- show_image(int ox, int oy, int x, int y)
- {
- if (!mi || !showmi)
- return;
-
- mv_ras_obj(mi->mraster, mi->w, mi->h, ox, oy, x, y);
- }
-
-
- /******************************************************************
- * Global entry point
- *****************************************************************/
-
- int
- do_merge(IPTR im)
- {
- short val;
- long dev;
-
- create_form_imerge();
- deactivate_all_forms();
- oim = im;
- mi = 0;
-
- /*
- * initialize and install handler to handle window manager's resize and
- * reposition events
- */
-
- merge_init(im, 0);
- install_wm_handler(merge_init);
-
- /* disable bounds checking */
-
- set_rubber_bounds(0, 0, 0, 0, 0);
-
- bit_show_form(imerge, FL_PLACE_MOUSE, 0, "Imerge");
-
- /* looping until ESC or done button is pressed */
- do
- {
- if (alignreq == 0 && ImageOK)
- {
- dev = rubber_info(win_id, &val,
- &ir->x, &ir->y, &ir->w, &ir->h, 2, 0);
- dev = bit_handle_event(dev, val);
- }
- else
- dev = bit_qread(&val);
- }
- while (!(dev == KEYBD && val == 27));
-
- /* clean up */
- remove_wm_handler(merge_init);
- rubber_finish();
- bit_hide_form(imerge);
- free_image(mi);
- fl_activate_all_forms();
- return 0;
- }
-
-
- /*************************************************************
- * find where the rubber should be (ix, iy). The current image
- * location is given by (xi, xf, w, h)
- *
- * Location request is defined as follows:
- *
- * 7 8 9
- * 17 19
- * 4 image 6
- * 11 13
- * 1 2 3
- *
- *************************************************************/
-
- /* ARGSUSED */
- static void
- get_location(IPTR im)
- {
- int xf = imr->x + imr->w - 1;
- int yf = imr->y + imr->h - 1;
- int xi = imr->x, yi = imr->y;
- int w = imr->w, h = imr->h;
- int iw = ir->w, ih = imr->h;
-
- switch (alignreq)
- {
- case 1:
- ir->x = xi;
- ir->y = yi - ih - sep;
- break;
- case 2:
- ir->x = xi + (w - iw) / 2;
- ir->y = yi - ih - sep;
- break;
- case 3:
- ir->x = xf - iw + 1;
- ir->y = yi - ih - sep;
- break;
- case 7:
- ir->x = xi;
- ir->y = yf + 1 + sep;
- break;
- case 8:
- ir->x = xi + (w - iw) / 2;
- ir->y = yf + 1 + sep;
- break;
- case 9:
- ir->x = xf - iw + 1;
- ir->y = yf + 1 + sep;
- break;
- case 6:
- ir->x = xf + 1 + sep;
- ir->y = yi + (h - ih) / 2;
- break;
- case 11:
- ir->x = xi - iw - sep;
- ir->y = yi;
- break;
- case 17:
- ir->x = xi - iw - sep;
- ir->y = yf - ih + 1;
- break;
- case 4:
- ir->x = xi - iw - sep;
- ir->y = yi + (h - ih) / 2;
- break;
- case 19:
- ir->x = xf + 1 + sep;
- ir->y = yf - ih + 1;
- break;
- case 13:
- ir->x = xf + 1 + sep;
- ir->y = yi;
- break;
- }
- }
-
- static void
- place_rubber(IPTR im)
- {
- int ox = ir->x, oy = ir->y;
-
- if (ir->w == 0 || ir->h == 0)
- return;
-
- get_location(im);
- set_current_window(win_id);
-
- rubber_moveto(&ir->x, &ir->y, &ir->w, &ir->h);
- show_image(ox, oy, ir->x, ir->y);
-
- rubber_show(alignreq ? 1 : 2); /* change rubber_color */
-
- }
-
- /******************************************************************
- * Initialize the rubber band location. If wme == 1, it is called
- * by the window manager envents handler or purposely not updating
- * current alignment reference
- ******************************************************************/
-
- static int
- merge_init(IPTR im, int wme)
- {
-
- if (!wme)
- {
- offx = offy = 0;
- imr = &imrect;
- copy_rect(imr, img_rect(im));
- ir = &iirect;
- ir->w = ir->h = 0;
- }
- else
- {
- /* image & window size might've been changed */
- imr->x = im->xi + offx;
- imr->y = im->yi + offy;
- }
- place_rubber(im);
- return 0;
- }
-
-
- /********** Load the image to merge *******************************/
-
- /*ARGSUSED*/
- static void
- load_cb(FL_OBJECT * ob, long q)
- {
- const char *fn = getfilename("Files to merge", ".", "*", "", 0);
- IPTR tmpi;
-
-
- if (!fn || !(tmpi = load_image(fn)))
- return;
-
- free_image(mi);
-
- /* show current image info, which was reset in load_image */
- update_image_info(imgptr);
-
- mi = tmpi;
- set_current_window(win_id);
- rubber_hide();
-
- ir->w = tmpi->w;
- ir->h = tmpi->h;
- get_location(imgptr);
- rubber_new(win_id, ir->x, ir->y, ir->w, ir->h, alignreq ? 1 : 2);
- }
-
- /*ARGSUSED*/
- static void
- top_bottom_cb(FL_OBJECT * ob, long q)
- {
- mergebot = fl_get_choice(ob) - 1;
- }
-
- /*ARGSUSED*/
- static void
- update_size_cb(FL_OBJECT * ob, long q)
- {
- merge_init(imgptr, 0);
- }
-
- /******************************************************************
- * Do the actual merging, taking into account the top/bottom
- * settings
- ******************************************************************/
-
- /*ARGSUSED*/
- static void
- merge_it(FL_OBJECT * ob, long q)
- {
- rgba_t **mat, fcolor;
- const Rect_t *sum, *uu;
-
- if (!ImageOK)
- return;
-
- /* figure out the new image size */
-
- sum = sum_rect(img_rect(oim), ir);
-
-
- /* merged image will always be in RGB */
- if (img_convert_type(oim, T_RGBA) || img_convert_type(mi, T_RGBA))
- return;
-
- show_busy("PleaseWait ...");
-
- /* get the new image matrix and initialize to the request bk color */
-
- mat = get_mat(sum->h, sum->w, sizeof(rgba_t));
- fcolor = Pack(fillc[0], fillc[1], fillc[2]);
- init_mat(mat, sum->h, sum->w, sizeof(rgba_t), fcolor);
-
- mi->xi = ir->x;
- mi->yi = ir->y;
- mi->xf = ir->x + ir->w - 1;
- mi->yf = ir->y + ir->h - 1;
-
- /*
- * always remember where the original image is by remembering the
- * distance from lower-left corner of the original image to the
- * lower-left corner of the merged image
- */
-
- offx = imr->x - sum->x;
- offy = imr->y - sum->y;
-
-
- /*
- * further optimization is possible in that for concatenation, the image
- * itself IS the submat and we can simple use the image matrix and thus
- * avoiding the submat operation
- */
-
- if (mergebot) /* new image at bottom */
- {
- put_submat(mat, sum->h, sum->w, mi->mraster,
- ir->y - sum->y, ir->x - sum->x,
- ir->h, ir->w, sizeof(rgba_t));
- put_submat(mat, sum->h, sum->w, oim->mraster,
- oim->yi - sum->y, oim->xi - sum->x,
- oim->h, oim->w, sizeof(rgba_t));
- }
- else
- {
- /* insert subimages */
- put_submat(mat, sum->h, sum->w, oim->mraster,
- oim->yi - sum->y, oim->xi - sum->x,
- oim->h, oim->w, sizeof(rgba_t));
- put_submat(mat, sum->h, sum->w, mi->mraster,
- ir->y - sum->y, ir->x - sum->x,
- ir->h, ir->w, sizeof(rgba_t));
- }
-
- /*
- * do requested operation on the overlapping part of the images only,
- * taking into consideration the top/bottom requests
- */
-
- if (mop->matop != O_NONE && (uu = union_rect(img_rect(oim), ir)))
- {
- rgba_t **m1, **m2;
- Rect_t urect;
- Rect_t *u = &urect;
-
- copy_rect(u, uu);
-
- /*
- * m1 is the input matrix, m2 is the image old image and mat is
- * the resulting image
- */
-
- m1 = get_subimage(mi, u->x, u->y, u->w, u->h);
- m2 = get_subimage(oim, u->x, u->y, u->w, u->h);
-
- set_mat_op(mop->matop);
- M_info("Merge", "Op=%s\n", mop->name);
-
- put_submat(mergebot ? m1 : m2, u->h, u->w, mergebot ? m2 : m1,
- 0, 0, u->h - 1, u->w - 1, sizeof(**m2));
-
- set_mat_op(O_NONE);
-
- put_submat(mat, sum->h, sum->w, mergebot ? m1 : m2,
- u->y - sum->y, u->x - sum->x,
- u->h, u->w, sizeof(rgba_t));
- free_mat(m1);
- free_mat(m2);
- }
-
- fill_image_struct(oim, mat, sum->h, sum->w, T_RGBA);
-
- set_current_window(win_id);
- set_display_mode(oim);
-
- /* don't move the image unless requested */
- if (!autosize)
- {
- oim->xi = sum->x;
- oim->yi = sum->y;
- oim->xf = oim->xi + sum->w - 1;
- oim->yf = oim->yi + sum->h - 1;
- Rectwrite(sum->x, sum->y,
- sum->x + sum->w - 1, sum->y + sum->h - 1, oim->raster);
- }
- else
- {
- oim->io->display(oim, 0, double_buf);
- }
-
- merge_init(oim, !autosize); /* re-initialize */
- end_busy();
- }
-
- /***************** Alignment information **************
- *
- * 7 8 9
- * 17 19
- * 4 6
- * 11 13
- * 1 2 3
- *******************************************************/
-
- #if 0
- extern void set_rubber_info_cb(void (*)(int, int, int, int));
- #endif
-
- /* ARGSUSED */
- static void
- alignment_cb(FL_OBJECT * ob, long q)
- {
- if (alignreq == 0) /* manual */
- {
- set_rubber_info_cb(0);
- end_rubber_info();
- }
-
- alignreq = q;
- place_rubber(imgptr);
- #if 0
- if (alignreq == 0)
- {
- set_rubber_info_cb(show_image);
- }
- #endif
- }
-
- /************ Terminating Merge function *************/
- /* ARGSUSED*/
- static void
- merge_done(FL_OBJECT * ob, long q)
- {
- fl_qenter(KEYBD, 27);
- }
-
- /************* Seperation from the image ***************/
- /*ARGSUSED*/
- static void
- sep_cb(FL_OBJECT * ob, long q)
- {
- sep = fl_get_counter_value(ob);
- place_rubber(imgptr);
- }
-
- #define FILLCI 300
-
- /***************** Fill color ***********************/
-
- /* ARGSUSED*/
- static void
- fc_cb(FL_OBJECT * ob, long q)
- {
- get_color(imgptr, fillc, 1);/* block */
- fl_mapcolor(FILLCI, fillc[0], fillc[1], fillc[2]);
- fl_redraw_object(ob);
- }
-
- /******** Get the requested operation struct *****/
- static void
- operation_cb(FL_OBJECT * ob, long q)
- {
- if ((q = fl_get_choice(ob)) > 0)
- mop = matops + q - 1;
- }
-
- static FL_OBJECT *ialign;
-
- static void
- create_form_imerge(void)
- {
- FL_OBJECT *obj;
- float dx, dy, x, y;
- Matop *m = matops, *ms = m + sizeof(matops) / sizeof(matops[0]);
-
- if (imerge)
- return;
-
- imerge = fl_bgn_form(FL_NO_BOX, 275.0, 250.0);
- obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 275.0, 250.0, "");
- obj = fl_add_text(FL_NT, 35.0, 210.0, 200.0, 30.0, "Image Merge");
- fl_set_object_lcol(obj, 4);
- fl_set_object_lsize(obj, 16.0);
- fl_set_object_align(obj, FL_ALIGN_CENTER);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
-
- obj = fl_add_button(FL_HB, 0, 0.0, 275.0, 250.0, "");
- fl_set_call_back(obj, help_cb, HELP_MERGE);
-
- dx = 75.0;
- dy = 25.0;
- x = 185.0;
- y = 175.0;
-
- /* Operations */
- obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
- fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
- fl_set_choice_fontsize(obj, 10.0);
-
- while (m < ms)
- {
- fl_addto_choice(obj, m->name);
- m++;
- }
-
- fl_set_choice(obj, 1);
- fl_set_call_back(obj, operation_cb, 0);
- y -= dy + 1;
-
- /* top/bottom */
- obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
- fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
- fl_set_choice_fontsize(obj, 10.0);
- fl_addto_choice(obj, "Top");
- fl_addto_choice(obj, "Bottom");
- fl_set_choice(obj, mergebot + 1);
- fl_set_call_back(obj, top_bottom_cb, 0);
- y -= dy + 5;
-
- dx = 75.0;
- dy = 25.0;
- x = 185.0;
-
- obj = fl_add_button(FL_NB, x, y, dx, dy, "FillColor");
- fl_set_object_lsize(obj, 10.0);
- fl_set_object_color(obj, FILLCI, FL_GREEN);
- fl_set_object_lcol(obj, FL_MAGENTA);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
- fl_set_call_back(obj, fc_cb, 0);
- y -= dy;
-
- obj = fl_add_button(FL_NB, x, y, dx, dy, "UpdateSize");
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, update_size_cb, 0);
- y -= dy;
-
- obj = fl_add_button(FL_NB, x, y, dx, dy, "Image2M");
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, load_cb, 0);
- y -= dy + 5;
-
- obj = fl_add_button(FL_NB, x, y, dx, dy, "Merge");
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, merge_it, 0);
- y -= dy;
-
- obj = fl_add_button(FL_NB, x, y, dx, dy, "Done");
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, merge_done, 0);
-
- /* Seperation control */
- obj = fl_add_counter(FL_NC, 30.0, 15.0, 130.0, 25.0, "");
- fl_set_counter_precision(obj, 0);
- fl_set_counter_bounds(obj, -MAXOFF, MAXOFF);
- fl_set_counter_step(obj, 1.0, 10.0);
- fl_set_counter_value(obj, sep);
- fl_set_call_back(obj, sep_cb, 0);
-
- /* all the alignment buttons */
- /* 7 8 9
- 17 19
- 4 6
- 11 13
- 1 2 3
- */
- ialign = fl_bgn_group();
-
- dx = dy = 30.0;
- y = 10;
-
- obj = fl_add_button(FL_RB, 55.0, y + 70.0, 90.0, 90.0, "Manual");
- fl_set_object_color(obj, 47, 12);
- fl_set_call_back(obj, alignment_cb, 0);
-
- /* center buttons */
- /* right-center */
- obj = fl_add_button(FL_RB, 145.0, y + 100.0, dx, dy, "@circle");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 6);
- fl_set_button(obj, alignreq == 6);
- /* bottom */
- obj = fl_add_button(FL_RB, 85.0, y + 40.0, dx, dy, "@circle");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 2);
- fl_set_button(obj, alignreq == 2);
- /* left */
- obj = fl_add_button(FL_RB, 25.0, y + 100.0, dx, dy, "@circle");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 4);
- fl_set_button(obj, alignreq == 4);
- /* top */
- obj = fl_add_button(FL_RB, 85.0, y + 160.0, dx, dy, "@circle");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 8);
- fl_set_button(obj, alignreq == 8);
-
- /* bottom two */
- obj = fl_add_button(FL_RB, 55.0, y + 40.0, dx, dy, "@4");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 1);
- fl_set_button(obj, alignreq == 1);
-
- obj = fl_add_button(FL_RB, 115.0, y + 40.0, dx, dy, "@6");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 3);
- fl_set_button(obj, alignreq == 3);
-
- /* top two */
- obj = fl_add_button(FL_RB, 55.0, y + 160.0, dx, dy, "@4");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 7);
- fl_set_button(obj, alignreq == 7);
- obj = fl_add_button(FL_RB, 115.0, y + 160.0, dx, dy, "@6");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 9);
- fl_set_button(obj, alignreq == 9);
-
- /* left two */
- obj = fl_add_button(FL_RB, 25.0, y + 70.0, dx, dy, "@2");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 11);
- fl_set_button(obj, alignreq == 11);
- obj = fl_add_button(FL_RB, 25.0, y + 130.0, dx, dy, "@8");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 17);
- fl_set_button(obj, alignreq == 17);
-
- /* right two */
- obj = fl_add_button(FL_RB, 145.0, y + 130.0, dx, dy, "@8");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 19);
- fl_set_button(obj, alignreq == 19);
- obj = fl_add_button(FL_RB, 145.0, y + 70.0, dx, dy, "@2");
- fl_set_object_lcol(obj, 1);
- fl_set_call_back(obj, alignment_cb, 13);
- fl_set_button(obj, alignreq == 13);
- fl_end_group();
- fl_end_form();
- }
-